package com.gitee.jjnnzb.jimmyrpc.core.provider;

import com.gitee.jjnnzb.jimmyrpc.core.annotation.RpcProvider;
import com.gitee.jjnnzb.jimmyrpc.core.entity.RpcRequest;
import com.gitee.jjnnzb.jimmyrpc.core.entity.RpcResponse;
import jakarta.annotation.PostConstruct;
import lombok.Data;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author Jjn
 * @since 2024-03-17 23:05
 */
@Data
public class ProviderBootstrap implements ApplicationContextAware {
    
    private ApplicationContext applicationContext;
    private Map<String, Object> skeletons = new HashMap<>();
    
    private void generateInterface(Object x) {
        Class<?>[] interfaces = x.getClass().getInterfaces();
        Class<?> firstInterface = interfaces[0];
        skeletons.put(firstInterface.getCanonicalName(), x);
    }
    
    @PostConstruct
    public void initProviders() {
        Map<String, Object> providers = applicationContext.getBeansWithAnnotation(RpcProvider.class);
        providers.forEach((name, bean) -> {
            System.out.println(name);
            generateInterface(bean);
        });
        
    }
    
    public RpcResponse invokeRequest(RpcRequest request) {
        Object bean = skeletons.get(request.getService());
        try {
            Method method = findTargetMethod(bean.getClass(), request.getMethod());
            Object result = method.invoke(bean, request.getArgs());
            return new RpcResponse().setData(result).setStatus(true);
        } catch (InvocationTargetException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
    
    private Method findTargetMethod(Class<?> aClass, String method) {
        Method[] methods = aClass.getMethods();
        for (Method m : methods) {
            if (Objects.equals(m.getName(), method)) {
                return m;
            }
        }
        return methods[0];
    }
}
